package util;

import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
//import java.nio.file.Files; // need java7 for this
import java.util.ArrayList;

import javax.swing.JFileChooser;
import javax.swing.JOptionPane;

import org.apache.commons.io.FileUtils;

import delaunay_triangulation.Delaunay_Triangulation;
import delaunay_triangulation.Triangle_dt;

import primatives.PointND;
import ui.Window_MainApp;
import ui.UIConst;

public class STLBReader
{
	private static void print_bytes(byte[] array)
	{
		for (int i = 0; i < array.length; i++) System.out.print(to_uint8(array[i]) + " ");
		System.out.println();
	}
	
	/** 
	 * Convert a byte into an uint8
	 * @param b
	 * @return
	 */
	private static int to_uint8(byte b) { return b & 0xFF; }
	
	/**
	 * Return another byte array which contains the data between array[start] to array[end]
	 * @param array
	 * @param start
	 * @param end
	 * @return
	 */
	private static byte[] subarray(byte[] array, int start, int end)
	{
		int length = end-start + 1;
		byte[] ret = new byte[length];
		for (int i = 0; i < length; i++) { ret[i] = array[start+i]; }
		return ret;
	}
	
	/**
	 * Convert a byte array of 12 values to 3-floats representing a vector in 3D
	 * @param array
	 * @return
	 */
	private static float[] to_vector(byte[] array)
	{
		float[] vec = new float[3];
		byte[] nx = subarray(array, 0, 3);
		byte[] ny = subarray(array, 4, 7);
		byte[] nz = subarray(array, 8, 11);
		
		vec[0] = ByteBuffer.wrap(nx).order(ByteOrder.nativeOrder()).getFloat();
		vec[1] = ByteBuffer.wrap(ny).order(ByteOrder.nativeOrder()).getFloat();
		vec[2] = ByteBuffer.wrap(nz).order(ByteOrder.nativeOrder()).getFloat();
		
		return vec;
	}
	
	/**
	 * Choose and read a stlb file through a file chooser and return a list of triangles.
	 * @return
	 */
	public static ArrayList<STLTriangle> read()
	{
		ArrayList<STLTriangle> triangles = new ArrayList<STLTriangle>();
		
		File input_stlb = null;
		JFileChooser fc = new JFileChooser();
        int returnVal = fc.showOpenDialog(null);

        if (returnVal == JFileChooser.APPROVE_OPTION)
        {
        	input_stlb = fc.getSelectedFile();
        }
        
        if (input_stlb != null)
        {
    		try
    		{
//            	byte[] data = Files.readAllBytes(input_stlb.toPath()); // requires java 7
    			byte[] data = FileUtils.readFileToByteArray(input_stlb);
            	triangles = process(data);
    		}
    		catch (IOException e)
    		{
    			e.printStackTrace();
    		}
        }
		
		return triangles;
	}

	/**
	 * Given an input path read the file as an stlb file and return a list of triangles.
	 * @param input
	 * @return
	 */
	public static ArrayList<STLTriangle> read(String input)
	{
		ArrayList<STLTriangle> triangles = new ArrayList<STLTriangle>();
		
		File input_stlb = new File(input);
		try
		{
//			byte[] data = Files.readAllBytes(input_stlb.toPath()); // requires java 7
			byte[] data = FileUtils.readFileToByteArray(input_stlb);
			triangles = process(data);
		}
		catch (IOException e)
		{
			e.printStackTrace();
		}
		
		return triangles;	
	}
	
	public static ArrayList<STLTriangle> process(byte[] data)
	{
		ArrayList<STLTriangle> triangles = new ArrayList<STLTriangle>();
		
    	// bytes 81-84 specify the number of faces in the reset of the byte array, corresponds to indices 80-83
    	int numberOfFaces = 0;
    	numberOfFaces |= to_uint8(data[83]) << 24;
    	numberOfFaces |= to_uint8(data[82]) << 16;
    	numberOfFaces |= to_uint8(data[81]) << 8;
    	numberOfFaces |= to_uint8(data[80]);
    	
    	System.out.println("Number of faces: " + numberOfFaces);
    	
    	// list of faces begins at index 84
    	int facet_begin = 84;
    	for (int i = 0; i < numberOfFaces; i++)
    	{
    		// each triangle if 5 bytes
    		int face_begin = facet_begin + 50 * i;
    		int face_end = face_begin + 50-1;
    		byte[] face_bytes = subarray(data, face_begin, face_end);
    		
    		byte[] normal_bytes = subarray(face_bytes, 0, 11);
    		byte[] v1_bytes = subarray(face_bytes, 12, 23);
    		byte[] v2_bytes = subarray(face_bytes, 24, 35);
    		byte[] v3_bytes = subarray(face_bytes, 36, 47);
    		
    		STLTriangle t = new STLTriangle();
    		t.normal = to_vector(normal_bytes);
    		t.v1 = to_vector(v1_bytes);
    		t.v2 = to_vector(v2_bytes);
    		t.v3 = to_vector(v3_bytes);
    		
    		triangles.add(t);
    	}
    	
    	return triangles;
	}
	
	public static void main(String[] args)
	{
		ArrayList<STLTriangle> triangles = STLBReader.read();
		
		// compute a list of strike and dips, then write them to a file
	}
}
